package com.jlf.controller.engine;

import com.jlf.controller.engine.entity.criterion.SchemaCriterionBatchInput;
import com.jlf.controller.engine.entity.criterion.SchemaCriterionDetailOutput;
import com.jlf.controller.engine.entity.criterion.SchemaCriterionInput;
import com.jlf.controller.engine.entity.criterion.SchemaCriterionQueryInput;
import com.jlf.core.annotation.restful.controller.RestfulController;
import com.jlf.core.annotation.restful.method.RestfulDelete;
import com.jlf.core.annotation.restful.method.RestfulGet;
import com.jlf.core.annotation.restful.method.RestfulPost;
import com.jlf.core.annotation.restful.method.RestfulPut;
import com.jlf.core.engine.domain.SchemaCriterionDO;
import com.jlf.core.engine.domain.SchemaDomainDO;
import com.jlf.core.engine.domain.SchemaFieldDO;
import com.jlf.core.engine.entity.criterion.AddCriterionWrapper;
import com.jlf.core.engine.entity.criterion.EditCriterionWrapper;
import com.jlf.core.engine.persistence.SchemaDomainPersistence;
import com.jlf.core.engine.persistence.SchemaFieldPersistence;
import com.jlf.core.engine.server.SchemaCriterionServer;
import com.jlf.core.error.Errors;
import com.jlf.core.error.exception.NoObjectException;
import com.jlf.core.error.exception.NullReferenceException;
import com.jlf.core.output.ResultException;
import com.jlf.core.server.entity.ListWrapper;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 模型查询条件的管理接口
 *
 * @author wujr
 * 2023/7/21
 * @version 1.0
 * 【变更历史】
 * [wujr 2023/7/21 1.0 新增]
 */
@Slf4j
@Tag(name = "模型领域检索条件管理接口")
@RestfulController(path = "/rest/jlf/core/engine/schema/criteria", name = "模型领域检索条件管理接口", domainClass = SchemaCriterionDO.class)
@RequiredArgsConstructor
public class SchemaCriterionController {
    private final SchemaCriterionServer schemaCriterionServer;
    private final SchemaDomainPersistence schemaDomainPersistence;
    private final SchemaFieldPersistence schemaFieldPersistence;

    @RestfulPost(code = "addSchemaCriteria", name = "新增模型检索条件", path = "/domain/{domainId}")
    public SchemaCriterionDO addSchemaCriteria(@PathVariable("domainId") Long domainId,
                                               @Valid @RequestBody SchemaCriterionInput input) throws Exception{
        SchemaDomainDO schemaDomain = schemaDomainPersistence.getById(domainId);
        if (schemaDomain == null){
            log.info("新增模型的检索条件，模型：{} 不存在", domainId);
            throw new NullReferenceException(SchemaCriterionDO.class, "模型不存在");
        }
        Set<String> classFieldCodes = new HashSet<>(input.getClassFieldCode());
        List<SchemaFieldDO> schemaFields = schemaFieldPersistence.loadByDomain(schemaDomain.getDomainCode(), classFieldCodes);
        if (schemaFields.size() != classFieldCodes.size()){
            log.info("新增模型的检索条件，本条件关联的字段不存在：{}", classFieldCodes);
            throw new NullReferenceException(SchemaCriterionDO.class, "字段不存在");
        }

        SchemaCriterionDO record = input.to();
        if (!record.isCriterionValid()){
            log.info("新增模型领域检索条件：{}，必须至少支持一种查询方式", record.getCriterionCode());
            throw new ResultException(Errors.API_PARAMETER, "必须至少支持一种查询方式");
        }
        record.setDomainCode(schemaDomain.getDomainCode());
        record.setClassFieldCode(StringUtils.join(classFieldCodes, ","));

        AddCriterionWrapper wrapper = new AddCriterionWrapper();
        wrapper.setRecord(record);
        wrapper.setSchemaFields(schemaFields);
        schemaCriterionServer.preAdd(wrapper);
        schemaCriterionServer.add(wrapper);
        return wrapper.getRecord();
    }
    @RestfulPost(code = "batchAddSchemaCriterion", name = "批量新增模型领域检索条件", path = "/domain")
    public void batchAddSchemaCriterion(@Valid @RequestBody SchemaCriterionBatchInput input) throws Exception{
        SchemaDomainDO schemaDomain = schemaDomainPersistence.getById(input.getDomainId());
        if (schemaDomain == null){
            log.info("批量新增模型领域检索条件，所属模型：{} 不存在", input.getDomainId());
            throw new NullReferenceException(SchemaCriterionDO.class, "模型领域不存在");
        }
        Set<String> classFieldCode = new HashSet<>();
        List<SchemaCriterionDO> records = new ArrayList<>();
        for (SchemaCriterionInput criterion : input.getCriteria()){
            SchemaCriterionDO record = criterion.to();
            if (!record.isCriterionValid()){
                log.info("批量新增模型领域检索条件：{}，必须至少支持一种查询方式", record.getCriterionCode());
                throw new ResultException(Errors.API_PARAMETER, "必须至少支持一种查询方式");
            }
            record.setDomainCode(schemaDomain.getDomainCode());
            Set<String> fieldCodes = new HashSet<>(criterion.getClassFieldCode());
            classFieldCode.addAll(fieldCodes);
            record.setClassFieldCode(StringUtils.join(fieldCodes, ','));
            records.add(record);
        }
        List<SchemaFieldDO> schemaFields = schemaFieldPersistence.loadByDomain(schemaDomain.getDomainCode(), classFieldCode);
        if (schemaFields.size() != classFieldCode.size()){
            log.info("批量新增模型的检索条件，本条件关联的字段不存在：{}", classFieldCode);
            throw new NullReferenceException(SchemaCriterionDO.class, "字段不存在");
        }
        schemaCriterionServer.add(records, schemaFields);
    }

    @RestfulPut(code = "editSchemaCriteria", name = "编辑模型检索条件", path = "/{criteriaId}")
    public SchemaCriterionDO editSchemaCriteria(@PathVariable("criteriaId") Long criteriaId,
                                                @Valid @RequestBody SchemaCriterionInput input) throws Exception{
        SchemaCriterionDO original = schemaCriterionServer.getById(criteriaId);
        if (original == null){
            log.info("编辑模型的检索条件：{}，该检索条件不存在", criteriaId);
            throw new NoObjectException(SchemaCriterionDO.class, "模型检索条件不存在");
        }
        Set<String> classFieldCodes = new HashSet<>(input.getClassFieldCode());
        List<SchemaFieldDO> schemaFields = schemaFieldPersistence.loadByDomain(original.getDomainCode(), classFieldCodes);
        if (schemaFields.size() != classFieldCodes.size()){
            log.info("编辑模型的检索条件，本条件关联的字段不存在：{}", classFieldCodes);
            throw new NullReferenceException(SchemaCriterionDO.class, "字段不存在");
        }
        SchemaCriterionDO record = input.to();
        if (!record.isCriterionValid()){
            log.info("编辑模型的检索条件：{}，必须至少支持一种查询方式", record.getCriterionCode());
            throw new ResultException(Errors.API_PARAMETER, "必须至少支持一种查询方式");
        }
        record.setId(original.getId());
        record.setClassFieldCode(StringUtils.join(classFieldCodes, ","));

        EditCriterionWrapper wrapper = new EditCriterionWrapper();
        wrapper.setOriginal(original);
        wrapper.setRecord(record);
        wrapper.setSchemaFields(schemaFields);
        schemaCriterionServer.preEdit(wrapper);
        schemaCriterionServer.edit(wrapper);
        return wrapper.getRecord();
    }

    @RestfulDelete(code = "deleteSchemaCriteria", name = "删除模型领域检索条件", path = "/{criteriaId}")
    public void deleteSchemaCriteria(@PathVariable("criteriaId") Long criteriaId) throws Exception{
        SchemaCriterionDO record = schemaCriterionServer.getById(criteriaId);
        if (record == null){
            log.info("删除模型的检索条件：{}，该条件不存在", criteriaId);
            throw new NoObjectException(SchemaCriterionDO.class, "模型检索条件不存在");
        }
        schemaCriterionServer.preDelete(record);
        schemaCriterionServer.delete(record);
    }

    @RestfulGet(code = "viewSchemaCriteriaDetail", name = "查看模型领域检索条件详情", path = "/{criteriaId}")
    public SchemaCriterionDetailOutput viewSchemaCriteriaDetail(@PathVariable("criteriaId") Long criteriaId) throws Exception{
        SchemaCriterionDO record = schemaCriterionServer.getById(criteriaId);
        if (record == null){
            log.info("查看模型的检索条件详情：{}，该条件不存在", criteriaId);
            throw new NoObjectException(SchemaCriterionDO.class, "模型检索条件不存在");
        }
        SchemaCriterionDetailOutput output = new SchemaCriterionDetailOutput(record);
        List<SchemaFieldDO> schemaFields = schemaFieldPersistence.loadByDomain(record.getDomainCode(), output.getClassFieldCode());
        List<SchemaCriterionDetailOutput.Field> fields = new ArrayList<>();
        for (SchemaFieldDO schemaField : schemaFields){
            SchemaCriterionDetailOutput.Field field = new SchemaCriterionDetailOutput.Field(schemaField);
            fields.add(field);
        }
        output.setDomainField(fields);
        return output;
    }

    @RestfulGet(code = "querySchemaCriteria", name = "查询模型领域检索条件")
    public ListWrapper<SchemaCriterionDetailOutput> querySchemaCriteria(SchemaCriterionQueryInput input,
                                                              @RequestParam(value = "pageNo", required = false, defaultValue = "1") int pageNo,
                                                              @RequestParam(value = "pageSize", required = false, defaultValue = "50") int pageSize){
        ListWrapper<SchemaCriterionDO> records = schemaCriterionServer.query(input, pageNo, pageSize);
        if (CollectionUtils.isEmpty(records.getRecord())){
            return ListWrapper.empty(records.getTotal());
        }
        List<SchemaCriterionDetailOutput> output = new ArrayList<>();
        for (SchemaCriterionDO schemaCriterion : records.getRecord()){
            output.add(new SchemaCriterionDetailOutput(schemaCriterion));
        }
        return new ListWrapper<>(records.getTotal(), output);
    }
}
